I am confused about the as const cast. I checked a few documents and videos but did not understand it fully.
My concern is what does the as const mean in the code below and what is the benefit of using it?
const args = [8, 5] as const;
const angle = Math.atan2(...args);
console.log(angle);
If you were to write const args = [8, 5], nothing would prevent you from then also writing args[0] = 23 or args.push(30) or anything else to modify that array. All you've done is tell TS/JS that the variable named args points to that specific array, so you can't change what it's referencing (e.g. you can't do args = "something else"). You can modify the array, you just can't change what its variable is pointing to.
On the other hand, adding as const to a declaration now really makes it constant. The whole thing is read-only, so you can't modify the array at all.
To clarify, as pointed out in the comments:
"really makes it constant" could imply that there is some runtime effect when there is none. At runtime, args.push(30) will still modify the array. All as const does is make it so that the TypeScript compiler will complain if it sees you doing it. – jcalz
as const only affects the compiler, and there is an exception to its read-only effect (see the comments). But in general, that's still the major use difference between const and as const. One is used to make a reference immutable and the other is used to make what's being referenced immutable.
That is a const assertion. Here is a handy post on them, and here is the documentation.
When we construct new literal expressions with const assertions, we can signal to the language that
- no literal types in that expression should be widened (e.g. no going from "hello" to string)
- object literals get readonly properties
- array literals become readonly tuples
With const args = [8, 5] as const;, the third bullet applies, and tsc will understand it to mean:
// Type: readonly [8, 5]
const args = [8, 5] as const;
// Ok
args[0];
args[1];
// Error: Tuple type 'readonly [8, 5]' of length '2' has no element at index '2'.
args[2];
Without the assertion:
// Type: number[]
const args = [8, 5];
// Ok
args[0];
args[1];
// Also Ok.
args[2];
In short words, it lets you create fully readonly objects, this is known as const assertion, at your code as const means that the array positions values are readonly, here's an example of how it works:
const args = [8, 5] as const;
args[0] = 3; // throws "Cannot assign to '0' because it is a read-only
args.push(3); // throws "Property 'push' does not exist on type 'readonly [8, 5]'"
You can see at the last thrown error, that args = [8, 5] as const is interpreted as args: readonly [8, 5], that's because the first declaration is equivalent to a readonly tuple.
There's a few exceptions for the asserts being 'fully readonly', you can check them here. However, the general benefit is the readonly behaviour that is added to all its object attributes.
const args = [8, 5];
// Without `as const` assert; `args` stills a constant, but you can modify its attributes
args[0] = 3; // -- WORKS
args.push(3); // -- WORKS
// You are only prevented from assigning values directly to your variable
args = 7; // -- THROWS ERROR
For more details, here's a list of other related question/answers that helped me understand the const assertion: